/*#########################################################################
# Ampache Adapter Server by Saggi Mizrahi.                                #
#                                                                         #
#   This program is free software; you can redistribute it and/or modify  #
#   it under the terms of the GNU General Public License as published by  #
#   the Free Software Foundation; either version 2 of the License, or     #
#   (at your option) any later version.                                   #
#                                                                         #
#   This program is distributed in the hope that it will be useful,       #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#   GNU General Public License for more details.                          #
#                                                                         #
#   You should have received a copy of the GNU General Public License     #
#   along with this program; if not, write to the                         #
#   Free Software Foundation, Inc.,                                       #
#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         #
##########################################################################*/

Importer.loadQtBinding("qt.core");
Importer.loadQtBinding("qt.xml");
Importer.loadQtBinding("qt.network");

Importer.include("common.js");

function AmpacheAdapter(acl)
{ 
  this._base = '/server/xml.server.php?';
  this.route = '^' + this._base;
  this.accounts = acl;
  this.auths = ['1'];
  this.uids = {};
  for (account in this.accounts)
  {
    this.uids[account] = md5(QUuid.createUuid().toString()).toHex();
  }
  

}

AmpacheAdapter.prototype.toString = function()
{
  return "[Ampache Adapter]";
};

AmpacheAdapter.prototype._processRequest = function(server, requset, response)
{
  if (requset.method != 'GET')
  {
    throw 403;
  }
  
  var args = {action:null, filter:null, auth:null,url:null, user:null, timestamp:null, limit:null, offset:null};
  for (arg in args)
  {
    if (requset.path.hasQueryItem(arg))
    {
      args[arg] = requset.path.queryItemValue(arg.toString());
    }
  }
  
  if ((args.action === null) || (args.action.match('^_')))
  {
    throw 404;
  }
  
  //alert(args.action + ":" + (!this.uids.hasOwnProperty(args.auth)) && (args.action != "handshake"));
  
  if (args.action != "handshake")
  {
    args.user = null;
    for (user in this.uids)
    {
      if (this.uids[user] == args.auth)
      {
	args.user = user;
      }
    }
    if (args.user == null)
    {
      throw 401;
    }
  }
  args.host = requset.headers["Host"];
  //alert(requset.headers["Host"]);
  try
  { 
    response.content = this[args.action](response, args);
  }
  catch(err)
  {
    
    response.code = 500;
    response.content = "<Error>" + err + "</Error>";
  }
};

AmpacheAdapter.prototype._selectAlbums = function(args, where)
{
  where = defaultArg(where, "");
  limit = defaultArg(args.limit, 5000);
  offset = defaultArg(args.offset, 0);
  
  q = "select albums.id, albums.name, albums.artist, artists.name , tracks.year, tracks.num " +
      "from albums join artists on albums.artist = artists.id join " +
      "(" +
      	"select tracks.album, years.name as year, count(*) as num " +
      	"from tracks join years on tracks.year = years.id " +
      	"group by album, year " +
      ") as tracks on albums.id = tracks.album " + where;
      
  if (limit > 0)
  {
    q += " LIMIT " + offset.toString() + " , " + limit.toString();
  }
  res = query(q);
  resXML = new QByteArray();
  w = new QXmlStreamWriter(resXML);
  w.setAutoFormatting(true);
  w.writeStartDocument();
  w.writeStartElement('root');
  for (var i = 0; i < res.length; i += 6)
  {
    albumId = res[i];
    albumName = res[i+1];
    artistId = res[i+2];
    artistName = res[i+3];
    year = res[i+4];
    trackNum = res[i+5];
    w.writeStartElement('album');
      w.writeAttribute('id', albumId);
      w.writeTextElement('name', albumName);
      w.writeStartElement('artist');
	w.writeAttribute('id', artistId);
	w.writeCharacters(artistName);
      w.writeEndElement();
      w.writeTextElement('year', year);
      w.writeTextElement('tracks', trackNum);
      w.writeTextElement('art', "http://" + args.host + this._base + "action=album_image&filter=" + albumId + "&auth=" + args.auth);
    w.writeEndElement();
  }
  w.writeEndElement();
  w.writeEndDocument();
  return resXML;
};

AmpacheAdapter.prototype._selectSongs = function(args, where)
{
  where = defaultArg(where, "");
  limit = defaultArg(args.limit, 5000);
  offset = defaultArg(args.offset, 0);
  
  q = "select tracks.id, tracks.title, tracks.artist, artists.name, tracks.album, albums.name, tracks.genre, genres.name, tracks.tracknumber, tracks.length, tracks.filesize, tracks.discnumber " +
      "from tracks join artists on tracks.artist = artists.id join albums on tracks.album = albums.id join genres on tracks.genre = genres.id " +
      where;
  if (limit > 0)
  {
    q += " LIMIT " + offset.toString() + " , " + limit.toString();
  }
  
  res = query(q);
  resXML = new QByteArray();
  w = new QXmlStreamWriter(resXML);
  w.setAutoFormatting(true);
  w.writeStartDocument();
  w.writeStartElement('root');
  for (var i = 0; i < res.length; i += 12)
  {
    songId = res[i];
    songName = res[i+1];
    artistId = res[i+2];
    artistName = res[i+3];
    albumId = res[i+4];
    albumName = res[i+5];
    genreId = res[i+6];
    genreName = res[i+7];
    tracknum = res[i+8];
    length = res[i+9];
    size = res[i+10];
    disc = res[i+11];

    if (disc > 0)
    {
      tracknum = disc * 100 + parseInt(tracknum, 10);
    }
    w.writeStartElement('song');
      w.writeAttribute('id', songId);
      w.writeTextElement('title', songName);
      w.writeStartElement('artist');
	w.writeAttribute('id', artistId);
	w.writeCharacters(artistName);
      w.writeEndElement();
      w.writeStartElement('album');
	w.writeAttribute('id', albumId);
	w.writeCharacters(albumName);
      w.writeEndElement();
      w.writeStartElement('genre');
	w.writeAttribute('id', genreId);
	w.writeCharacters(genreName);
      w.writeEndElement();
      w.writeTextElement('track', tracknum);
      w.writeTextElement('time', length);
      w.writeTextElement('size', size);
      w.writeTextElement('url', "http://" + args.host + this._base + "action=song_stream&filter=" + songId + "&auth=" + args.auth);
      w.writeTextElement('art', "http://" + args.host + this._base + "action=album_image&filter=" + albumId + "&auth=" + args.auth);
    w.writeEndElement();
  }
  w.writeEndElement();
  w.writeEndDocument();
  return resXML;
};

AmpacheAdapter.prototype._selectArtists = function (args, where)
{
  where = defaultArg(where, "");
  limit = defaultArg(args.limit, 5000);
  offset = defaultArg(args.offset, 0);
  
  q = "select artists.id, artists.name, albumsnum.num, tracknum.num " +
      "from artists join " +
	"(" + 
	"select artists.id as id, count(*) as num " +
	"from artists join albums on artists.id = albums.artist " +
	"group by artists.id " +
	") as albumsnum on albumsnum.id = artists.id join " +
	"(" +
	"select artists.id as id, count(*) as num " +
	"from artists join tracks on tracks.artist = artists.id " +
	"group by artists.id " +
	") as tracknum on tracknum.id = artists.id " + where;
  if (limit > 0)
  {
    q += " LIMIT " + offset.toString() + " , " + limit.toString();
  }
  
  res = query(q);
  resXML = new QByteArray();
  w = new QXmlStreamWriter(resXML);
  w.setAutoFormatting(true);
  w.writeStartDocument();
  w.writeStartElement('root');
  for (var i = 0; i < res.length; i += 4)
  {
    id = res[i];
    name = res[i+1];
    albums = res[i+2];
    songs = res[i+3];
    w.writeStartElement('artist');
      w.writeAttribute('id', id);
      w.writeTextElement('name', name);
       w.writeTextElement('albums', albums);
      w.writeTextElement('songs', songs);
    w.writeEndElement();
  }
  w.writeEndElement();
  w.writeEndDocument();
  return resXML;
};

AmpacheAdapter.prototype._selectGenres = function (args, where)
{
  //TODO : finish this
  resXML = new QByteArray();
  w = new QXmlStreamWriter(resXML);
  w.setAutoFormatting(true);
  w.writeStartDocument();
  w.writeStartElement('root');
  w.writeEndElement();
  w.writeEndDocument();
  return resXML;
};

AmpacheAdapter.prototype.handshake = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  timestamp = args.timestamp;
  auth = args.auth;
  username = args.user;
  if (!this.accounts.hasOwnProperty(username)) {
    throw 401;
  }
  h = md5(timestamp + this.accounts[username]).toHex();
  if (h != new QByteArray(auth)) {
    throw 401;
  }
  debug('handshake:' + username);
  res = new QByteArray();
  w = new QXmlStreamWriter(res);
  w.setAutoFormatting(true);
  w.writeStartDocument();
  w.writeStartElement('root');
    w.writeTextElement('auth', this.uids[username]);
    w.writeTextElement('version', '3.4.0');
    w.writeTextElement('songs', Amarok.Collection.totalTracks());
    w.writeTextElement('artists', Amarok.Collection.totalArtists());
    w.writeTextElement('albums', Amarok.Collection.totalAlbums());
  w.writeEndElement();
  w.writeEndDocument();
  return res;
};

AmpacheAdapter.prototype.song_stream = function(resp, args)
{
  resp.headers['Content-Type'] = "audio/mpeg";
  q = "select urls.rpath " +
      "from urls join tracks on tracks.url = urls.id " +
      "where tracks.id = " + args.filter;
  res = query(q);
  f = new QFile("/" + res[0]);
  f.open(QIODevice.ReadOnly);
  return f;
};
AmpacheAdapter.prototype.album_image = function(resp, args)
{
  resp.headers['Content-Type'] = "image/png";
  q = "select images.path " +
      "from images join albums on albums.image = images.id " +
      "where albums.id =  " + args.filter;
  res = query(q);
  f = new QFile(res[0]);
  f.open(QIODevice.ReadOnly);
  return f;
};

AmpacheAdapter.prototype.artists = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    return this._selectArtists(args);
  }
  else
  {
    return this._selectArtists(args, 'where artists.name like "%' +  args.filter + '%"');
  }
};

AmpacheAdapter.prototype.artist_songs = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (!args.hasOwnProperty('filter')) {
    throw 404;}
  return this._selectSongs(args, "where tracks.artist = " + args.filter);
};

AmpacheAdapter.prototype.artist_albums = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    throw 404;
  }
  return this._selectAlbums(args, "where albums.artist = " + args.filter);
};

AmpacheAdapter.prototype.albums = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    return this._selectAlbums(args);
  }
  else
  {
    return this._selectAlbums(args, 'where albums.name like "%' +  args.filter + '%"');
  }
};

AmpacheAdapter.prototype.album_songs = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (!args.hasOwnProperty('filter')) {
    throw 404;}
  return this._selectSongs(args, "where tracks.album = " + args.filter);
};

AmpacheAdapter.prototype.genres = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    return this._selectGenres(args);
  }
  else
  {
    return this._selectGenres(args, 'where genre.name like "%' +  args.filter + '%"');
  }
};

AmpacheAdapter.prototype.genre = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    throw 404;
  }
  return this._selectGenres(args, "where genre.id = " + args.filter);
};

AmpacheAdapter.prototype.genre_artists = function(resp, args)
{
  //TODO : this
  resp.headers['Content-Type'] = "text/xml";
  return this._selectGenres(args);
};

AmpacheAdapter.prototype.genre_albums = function(resp, args)
{
  //TODO : this
  resp.headers['Content-Type'] = "text/xml";
  return this._selectGenres(args);
};

AmpacheAdapter.prototype.genre_songs = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (!args.hasOwnProperty('filter')) {
    throw 404;}
  return this._selectSongs(args, "where genre.id = " + args.filter);
};

AmpacheAdapter.prototype.songs = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (args.filter === null) {
    return this._selectSongs(args);
  }
  else
  {
    return this._selectSongs(args, 'where tracks.title like "%' +  args.filter + '%"');
  }
};

AmpacheAdapter.prototype.song = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (!args.hasOwnProperty('filter')) {
    throw 404;}
  return this._selectSongs(args, "where track.id = " + args.filter);
};
AmpacheAdapter.prototype.url_to_song = function(reps, args)
{
  if (!args.hasOwnProperty(url)) {
    throw 404;}
  regx = "http://" + args.host + this._base + "action=song_stream&filter=(\d+)&auth=" + args.auth;
  m = url.match(regx);
  if (!m)
  {
    throw 404;
  }
  return this._selectSongs(args, "where track.id = " + m[1]);
};
AmpacheAdapter.prototype.playlists = function(resp, args)
{};
AmpacheAdapter.prototype.playlist = function(resp, args)
{};
AmpacheAdapter.prototype.playlist_songs = function(resp, args)
{};
AmpacheAdapter.prototype.search_songs = function(resp, args)
{
  resp.headers['Content-Type'] = "text/xml";
  if (!args.hasOwnProperty('filter')) {
    throw 404;}
  like = ' like "%' + args.filter + '%" ';
  q = 'where artists.name LIKE or tracks.title LIKE or albums.name LIKE or genres.name LIKE'.replace('LIKE', like);
  return this._selectSongs(args, q);
};